<cfcomponent displayname="svnService" output="false" hint="I live to authenticate users.">


<!---
	Above is all injected stuff
 --->

	<cffunction name="dumpvar">
	  <cfargument name="var">
	  <cfargument name="ab" default="true">
	  <cfdump var="#var#">
	  <cfif arguments.ab><cfabort></cfif>
	</cffunction>

	<cffunction name="init" returntype="any" output="false" hint="Constructor">
		<cfargument name="svnConfiguration" required="true" />
		<cfargument name="loader" required="true" />
		<cfscript>
			var repositoryUrl = "";
			var protocol = "";
			variables._config = arguments.svnConfiguration;
			variables._loader = arguments.loader;
			repositoryUrl = variables._config.getConfigSetting("RepositoryURL");
			protocol = lcase(left(repositoryUrl,4));
			if(protocol eq "http") {
				this.drf = loader.create("org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory").setup();
				this.repoFactory = loader.create("org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory");
			} else if (protocol eq "file") {
				this.drf = loader.create("org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory").setup();
				this.repoFactory = loader.create("org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory");
				if (NOT fileExists(replaceNoCase(repositoryUrl,"file:///","")&"/format")) {
					createRepository(replaceNoCase(repositoryUrl,"file:///",""));
				}
			} else if (left(protocol,3) eq "svn") {
				this.drf = loader.create("org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactory").setup();
				this.repoFactory = loader.create("org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactory");
			}
			this.svnurl = loader.create("org.tmatesoft.svn.core.SVNURL");
//		  repository = loader.create("org.tmatesoft.svn.core.SVNURL");
			this.wcutil = loader.create("org.tmatesoft.svn.core.wc.SVNWCUtil");

			compileResults = compile(getDirectoryFromPath(getMetaData(this).path) & "../lib/svnWrap.java");
//			compileResults = compile(getDirectoryFromPath(getMetaData(this).path) & "../lib/ZipExport.java");
//			compileResults = compile(getDirectoryFromPath(getMetaData(this).path) & "../lib/cfsvn/export/Export.java","/www/cfmappings/actionpacks/cfsvn/lib/ZipExport.jar");
			compileResults = compile(getDirectoryFromPath(getMetaData(this).path) & "../lib/Exporter.java",getDirectoryFromPath(getMetaData(this).path) & "../lib/");
		</cfscript>

		<cfif compileResults["errors"] neq "">
			<cflog text="#compileResults["errors"]#">
		<!--- 
			<pre><cfoutput>#compileResults["errors"]#</cfoutput></pre>
			<cfabort>
		 --->
		</cfif>
		<cfreturn this />
	</cffunction>

<cffunction name="loadDirectory" hint="Loads the JAR file paths into the array" access="public" returntype="array" output="false">
	<cfargument name="path" hint="The path to oad" type="string" required="Yes">
	<cfargument name="library" hint="The array of classpaths" type="array" required="Yes">
	<cfscript>
		var qJars = 0;
	</cfscript>
	<cfif right(arguments.path,1) neq "/">
		<cfset arguments.path = arguments.path & "/">
	</cfif>
	<cfdirectory action="list" directory="#arguments.path#" filter="*.jar" name="qJars">	
	<cfloop query="qJars">
		<cfscript>
			ArrayAppend(arguments.library, arguments.path & name);
		</cfscript>
	</cfloop>	
	<cfscript>
		ArrayAppend(arguments.library, arguments.path);
		return arguments.library;
	</cfscript>
</cffunction>

	<cffunction name="compile" access="public" output="false" hint="compiles java files">
		<cfargument name="srcdir">
		<cfargument name="classpath" default="">
		<cfargument name="outFileDir" default="#arguments.srcdir#">
		<cfscript>
			var paths = loadDirectory(arguments.classpath,listToArray(getDirectoryFromPath(getMetaData(this).path) & "../lib/jdt-compiler-3.1.1.jar"));
//			var wee = dumpvar(paths);
			var loader = createObject("component", "actionpacks.apputils.model.javaloader.JavaLoader").init(paths,true,false);
			var compiler = loader.create('org.eclipse.jdt.internal.compiler.batch.Main');
			var didCompile = structNew();
			// get the system class path
			var	system = CreateObject("java", "java.lang.System");
			var filesep = system.getProperty("file.separator");
			var	outStream = CreateObject("java","java.io.ByteArrayOutputStream").init();
			var	outS = createObject("java","java.io.ByteArrayOutputStream").init();
			var	errS = createObject("java","java.io.ByteArrayOutputStream").init();
			var	outWriter = createObject("java","java.io.PrintWriter").init(outS);
			var	errWriter = createObject("java","java.io.PrintWriter").init(errS);
			arguments.outFileDir = getDirectoryFromPath(arguments.outFileDir);
			// set the class deliminator for windows/linux
			switch(filesep){
				case "/":
					classdelim = ":";
				break;
				case "\":
					classdelim = ";";
				break;
			}
			if (arguments.classpath eq "") {
				syslibpath = replacenocase(system.getProperty("java.library.path"),'../lib','lib');
				//classpath = """" & system.getProperty("java.class.path") & classdelim & system.getProperty("java.library.path") & classdelim & arrayToList(variables._loader.queryJars(),classdelim) &"""" ;
				classpath = """" & system.getProperty("java.class.path") & classdelim & syslibpath &"""" ;
			}
			else {
				//classpath = """" & arguments.classpath & classdelim &  arrayToList(variables._loader.queryJars(),classdelim)  &"""" ;
				classpath = """" & arguments.classpath & """";
			}
			didCompile["outFileDir"] = arguments.outFileDir;
			didCompile["command"] = "compile -nowarn -classpath #arrayToList(paths,classdelim)# #arguments.srcdir# -d #arguments.outFileDir#";
			//didCompile["success"] = compiler.compile("-nowarn -sourcepath #sourcepath# -classpath #classpath# #arguments.javaFile# -d #arguments.outFileDir#",outWriter,errWriter);
			didCompile["success"] = compiler.compile("-nowarn -classpath #arrayToList(paths,classdelim)# #arguments.srcdir# -d #arguments.outFileDir#",outWriter,errWriter);
			didCompile["errors"] = replace(errS.toString(),chr(13)&chr(10),"<br>","all");
			didCompile["out"] = outS.toString();
			outStream.close();
			outS.close();
			errS.close();
			outWriter.close();
			errWriter.close();
			return didCompile;
		</cfscript>
	</cffunction>


	<cffunction name="compile2">
		<cfargument name="javaFile">
		<cfargument name="classpath" default="">
		<cfargument name="outFileDir" default="#listDeleteAt(arguments.javaFile,listLen(arguments.javaFile,"/"),"/")#">
		<cfscript>
			var compiler = variables._loader.create('org.eclipse.jdt.internal.compiler.batch.Main');
			var didCompile = structNew();
			// get the system class path
			var system = CreateObject("java", "java.lang.System");
			var filesep = system.getProperty("file.separator");
			var outStream = CreateObject("java","java.io.ByteArrayOutputStream").init();
			var outS = createObject("java","java.io.ByteArrayOutputStream").init();
			var errS = createObject("java","java.io.ByteArrayOutputStream").init();
			var outWriter = createObject("java","java.io.PrintWriter").init(outS);
			var errWriter = createObject("java","java.io.PrintWriter").init(errS);
			// set the class deliminator for windows/linux
			switch(filesep){
				case "/":
					classdelim = ":";
				break;
				case "\":
					classdelim = ";";
				break;
			}
			if (arguments.classpath eq "") {
				//classpath = """" & system.getProperty("java.class.path") & classdelim & system.getProperty("java.library.path") & classdelim & arrayToList(variables._loader.queryJars(),classdelim) &"""" ;
				classpath = """" & system.getProperty("java.class.path") & classdelim & system.getProperty("java.library.path") & classdelim & arrayToList(variables._loader.queryJars(),classdelim) &"""" ;
			}
			else {
				classpath = """" & arguments.classpath & classdelim &  arrayToList(variables._loader.queryJars(),classdelim)  &"""" ;
			}
			sourcepath = """" & "/www/cfmappings/actionpacks/cfsvn/lib" &"""" ;
			didCompile["outFileDir"] = arguments.outFileDir;
			didCompile["command"] = "-classpath #classpath# #arguments.javaFile#";
			//didCompile["success"] = compiler.compile("-nowarn -sourcepath #sourcepath# -classpath #classpath# #arguments.javaFile# -d #arguments.outFileDir#",outWriter,errWriter);
			didCompile["success"] = compiler.compile("-nowarn -classpath #classpath# #arguments.javaFile# -d #arguments.outFileDir#",outWriter,errWriter);
			didCompile["errors"] = replace(errS.toString(),chr(13)&chr(10),"<br>","all");
			didCompile["out"] = outS.toString();
			outStream.close();
			outS.close();
			errS.close();
			outWriter.close();
			errWriter.close();
			return didCompile;
		</cfscript>
	</cffunction>
		
	<cffunction name="getConfigSetting" access="private" returntype="string" output="false">
		<cfargument name="name" required="true" type="string" />
		<cfreturn variables._config.getConfigSetting(arguments.name) />
	</cffunction>

	<cffunction name="setConfigSetting" access="private" returntype="string" output="false">
		<cfargument name="name" required="true" type="string" />
		<cfreturn variables._config.setConfigSetting(arguments.name) />
	</cffunction>

	<cffunction name="getLatestRevision" access="private" returntype="any" output="false">
		<cfreturn getRepository().getLatestRevision()>
	</cffunction>

	<cffunction name="getExportDirectory" access="public" returntype="any" output="false">
			<cfreturn variables._config.getConfigSetting("exportDirectory") />
	</cffunction>


	<cffunction name="getAuthManager" access="private" returntype="any" output="false">
		<cfargument name="user" default="#variables._config.getConfigSetting("Username")#">
		<cfargument name="pass" default="#variables._config.getConfigSetting("Password")#">
		<cfscript>
			var username = arguments.user;
			var password = arguments.pass;
			var authManager = this.wcutil.createDefaultAuthenticationManager(username,password);
			return authManager;
		</cfscript>
	</cffunction>
	
	<cffunction name="getRepository" access="private" returntype="any" output="false">
		<cfargument name="repoUrl" default="#variables._config.getConfigSetting("RepositoryURL")#">
		<cfargument name="user" default="#variables._config.getConfigSetting("Username")#">
		<cfargument name="pass" default="#variables._config.getConfigSetting("Password")#">
		<cfscript>
			var repositoryUrl = arguments.repoUrl;
			var username = arguments.user;
			var password = arguments.pass;
			var repository = this.repoFactory.create(this.svnurl.parseURIEncoded(repositoryUrl));
			var authManager = getAuthManager(username,password);
			if (username NEQ ""){
				repository.setAuthenticationManager(authManager);
			}
			//	dumpvar(this,true);
			return repository;
		</cfscript>
	</cffunction>

	<cffunction name="resourcePath" access="private">
		<cfargument name="repos" required="true" />
		<cfargument name="resource" required="true" />
		<cfscript>
			var repository = arguments.repos;
			var resourceURI1 = repository.getLocation().getPath() & arguments.resource;
			var resourceURI = replacenocase(resourceURI1,repository.getRepositoryRoot(false).getPath(),"");
		</cfscript>
		<cfreturn resourceURI>
	</cffunction>
	
	<cffunction name="getNodeKind" access="private">
		<cfargument name="repos" required="true" />
		<cfargument name="resource" required="true" />
		<cfargument name="revision" default="-1" />
		<cfscript>
			var repository = arguments.repos;
			var resourceURI = resourcePath(repository,resource);
			var nodeKind = "";
			try {
      	nodeKind = repository.checkPath(JavaCast("string",resourceURI),JavaCast("int",arguments.revision));
			} catch (err any) {
      	nodeKind = repository.checkPath(JavaCast("string",resourceURI),JavaCast("int",arguments.revision));
			}
		</cfscript>
		<cfreturn nodeKind>
	</cffunction>

	<cffunction name="resourceExists" output="false" description="Fetch a log of a given revision" returntype="boolean">
		<cfargument name="repos" required="true">
		<cfargument name="resourceURL" type="string" required="true">
		<cfargument name="revision" default="-1">
			<cfscript>
				var repository = arguments.repos;
				var NodeKind = getNodeKind(repository,arguments.resourceURL);
		  	if(nodeKind.compareTo(nodeKind.NONE) EQ 0) {
		  		return false;
		  	} else {
		  		return true;
		  	}
		</cfscript>
	</cffunction>

	<cffunction name="createRepository" output="false" description="create an SVN repository" returntype="any">
		<cfargument name="repositoryFilePath" required="true">		
		<cfargument name="overwrite" default="false">
		<cfargument name="propRevisions" default="false">
<!---
 		<cfset var repoFactory = variables._loader.create("org.tmatesoft.svn.core.internal.io.SVNRepositoryFactory")>
 --->
		<cfset var repoFile = createObject("java","java.io.File").init(arguments.repositoryFilePath)>
	  <cfset var repo = this.repoFactory.createLocalRepository( repoFile, javacast("null",""), true , false )>
	  <cfdump var="#repo#"><cfabort>
	</cffunction>

	<cffunction name="List" output="false" description="Retrieve a list of children for a resource" returntype="query">
		<cfargument name="Resource" type="string" required="true">
		<cfset var Q=QueryNew("Name,Author,Message,Date,Kind,Path,Revision,Size,URL,Content")>
		<cfset var ent=CreateObject("java","java.util.LinkedHashSet").init(16)>
		<cfset var i="">
		<cfset var f="">
		<cfset var u="">
		<cfset var repositoryUrl = variables._config.getConfigSetting("RepositoryURL")>
		<cfset var repository = getRepository()>
		<cfset var NodeKind = getNodeKind(repository,arguments.Resource) />
		<cfset resource = resourcePath(repository,resource) />
		<cfif NodeKind EQ NodeKind.DIR>
			<cfset repository.getDir(JavaCast("string",Arguments.Resource),JavaCast("int",-1),false,ent)>
			<cfset i=ent.iterator()>
			<cfloop condition="i.hasNext()">
				<cfset f=i.next()>
				<cfset QueryAddRow(Q)>
				<cfset Q.Name[Q.RecordCount]=f.getName()>
				<cfset Q.Author[Q.RecordCount]=f.getAuthor()>
				<cfset Q.Message[Q.RecordCount]=f.getCommitMessage()>
				<cfset Q.Date[Q.RecordCount]=f.getDate()>
				<cfset Q.Kind[Q.RecordCount]=f.getKind().toString()>
				<cfset Q.Path[Q.RecordCount]=f.getRelativePath()>
				<cfset Q.Revision[Q.RecordCount]=f.getRevision()>
				<cfset Q.Size[Q.RecordCount]=f.getSize()>
				<cfset u=f.getURL().toString()>
				<cfif Left(u,Len(repositoryUrl)) EQ repositoryUrl><cfset u=Mid(u,Len(repositoryUrl)+1,Len(u))></cfif>
				<!--- TODO: something different? remove repository path for now --->
				<cfset repositoryUrl = replaceNoCase(repositoryUrl,"file:////","file:///","all")>
				<cfset u = replaceNoCase(u,repositoryUrl,"","all")>
				<cfset Q.URL[Q.RecordCount]=u>
			</cfloop>
			<cfquery dbtype="query" name="Q">
			SELECT *
			FROM Q
			ORDER BY Kind, URL, Revision DESC
			</cfquery>
		</cfif>
		<cfreturn Q>
	</cffunction>
	
	<cffunction name="FileVersion" output="false" description="Retrieve the specific version of a file" returntype="query">
		<cfargument name="Resource" type="string" required="true">
		<cfargument name="Version" type="numeric" default="-1">
		<cfset var Q=QueryNew("Name,Author,Message,Date,Kind,Path,Revision,Size,URL,Content,MimeType")>
		<cfset var props=CreateObject("java","java.util.HashMap").init(16)>
		<cfset var out=CreateObject("java","java.io.ByteArrayOutputStream").init()>
		<cfset var MimeType="">
		<cfset var PageContext=getPageContext()>
		<cfset var repository = getRepository()>
		<cfset var NodeKind = getNodeKind(repository,arguments.Resource,arguments.version) />
		<cfset resource = resourcePath(repository,resource) />
		<cfif NodeKind.compareTo(NodeKind.FILE) EQ 0>
			<cfset repository.getFile(JavaCast("string",Arguments.Resource),JavaCast("int",Arguments.Version),props,out)>
			<cfset QueryAddRow(Q)>
			<cfset Q.Name[Q.RecordCount]=ListLast(Arguments.Resource,"/")>
			<cfif StructKeyExists(props,"svn:entry:last-author")>
				<cfset Q.Author[Q.RecordCount]=props["svn:entry:last-author"]>
			</cfif>
			<cfset Q.Date[Q.RecordCount]=CreateObject("java", "java.text.SimpleDateFormat").init("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'").parse(props["svn:entry:committed-date"], CreateObject("java", "java.text.ParsePosition").init(0))>
			<cfset Q.Kind[Q.RecordCount]="file">
			<cfset Q.Path[Q.RecordCount]=Mid(Arguments.Resource,1,Len(Arguments.Resource))>
			<cfset Q.Revision[Q.RecordCount]=props["svn:entry:committed-rev"]>
			<cfset Q.Size[Q.RecordCount]=out.size()>
			<cfset Q.URL[Q.RecordCount]=Mid(Arguments.Resource,1,Len(Arguments.Resource))>
			<cfset Q.Content[Q.RecordCount]=out.toByteArray()>
			<cfset MimeType=PageContext.getServletContext().getMimeType(Q.Name[Q.RecordCount])>
			<cfif NOT IsDefined("MimeType")>
				<cfset FileExt=LCase(ListLast(Q.Name[Q.RecordCount],"."))>
				<cfswitch expression="#FileExt#">
					<cfcase value="cfc,cfm,cfml,js,pl,plx,php,php4,php5,asp,aspx,sql"><cfset MimeType="text/plain"></cfcase>
					<cfcase value="jpg,jpeg,png,gif,ico"><cfset MimeType="image/"&FileExt></cfcase>
					<cfcase value="xml,html,htm"><cfset MimeType="text/"&FileExt></cfcase>
					<cfdefaultcase><cfset MimeType="application/octet-stream"></cfdefaultcase>
				</cfswitch>
			</cfif>
			<cfset Q.MimeType[Q.RecordCount]=MimeType>
		</cfif>
		<cfreturn Q>


	</cffunction>
	
	<cffunction name="History" output="false" description="Fetch a history of a given resource" returntype="query">
		<cfargument name="Resource" type="string" required="true">
		<cfset var Q=QueryNew("Name,Author,Message,Date,Kind,Path,Revision,Size,URL,Content")>
		<cfset var ent=CreateObject("java","java.util.LinkedHashSet").init(16)>
		<cfset var i="">
		<cfset var f="">
		<cfset var u="">
		<cfset var lastRev=-1>
		<cfset var repository = getRepository()>
		<cfset var repositoryUrl = variables._config.getConfigSetting("RepositoryURL")>
		<cfset var NodeKind = getNodeKind(repository,arguments.Resource) />
		<cfif NodeKind.compareTo(NodeKind.FILE) EQ 0>
			<cfset u=ArrayNew(1)>
			<cfset ArrayAppend(u,arguments.resource)>
			<cfset lastRev=repository.getLatestRevision()>
			<cfset repository.log(u,ent,JavaCast("int",0),JavaCast("int",lastRev),false,true)>
			<cfset i=ent.iterator()>
			<cfloop condition="i.hasNext()">
				<cfset f=i.next()>
				<cfset QueryAddRow(Q)>
				<cfset Q.Message[Q.RecordCount]=f.getMessage()>
				<cfset Q.Date[Q.RecordCount]=f.getDate()>
				<cfset Q.Author[Q.RecordCount]=f.getAuthor()>
				<cfset Q.Revision[Q.RecordCount]=f.getRevision()>
				<cfset Q.Path[Q.RecordCount]=Mid(Arguments.Resource,1,Len(Arguments.Resource))>
				<cfset Q.Name[Q.RecordCount]=ListLast(Arguments.Resource,"/")>
				<cfset Q.Kind[Q.RecordCount]="file">
			</cfloop>
			<cfquery dbtype="query" name="Q">
			SELECT *
			FROM Q
			ORDER BY Revision DESC
			</cfquery>
		<cfelse>
			<cfset repository.getDir(JavaCast("string",Arguments.Resource),JavaCast("int",-1),false,ent)>
			<cfset i=ent.iterator()>
			<cfloop condition="i.hasNext()">
				<cfset f=i.next()>
				<cfset QueryAddRow(Q)>
				<cfset Q.Name[Q.RecordCount]=f.getName()>
				<cfset Q.Author[Q.RecordCount]=f.getAuthor()>
				<cfset Q.Message[Q.RecordCount]=f.getCommitMessage()>
				<cfset Q.Date[Q.RecordCount]=f.getDate()>
				<cfset Q.Kind[Q.RecordCount]=f.getKind().toString()>
				<cfset Q.Path[Q.RecordCount]=f.getRelativePath()>
				<cfset Q.Revision[Q.RecordCount]=f.getRevision()>
				<cfset Q.Size[Q.RecordCount]=f.getSize()>
				<cfset u=f.getURL().toString()>
				<cfif Left(u,Len(repositoryUrl)) EQ repositoryUrl><cfset u=Mid(u,Len(repositoryUrl)+1,Len(u))></cfif>
				<cfset Q.URL[Q.RecordCount]=u>
			</cfloop>
			<cfquery dbtype="query" name="Q">
			SELECT *
			FROM Q
			ORDER BY Kind, URL, Revision DESC
			</cfquery>
		</cfif>
		<cfreturn Q>
	</cffunction>

	<cffunction name="changeSet" output="false" description="Fetch a log of a given revision" returntype="query">
		<cfargument name="firstRevision" type="string" required="true">
		<cfargument name="lastRevision" type="string" required="true">
		<cfset var repository = getRepository()>
		<cftry>
			<cfscript>
				svnWrap = variables._loader.create('svnWrap');
				logEntries = svnWrap.getLogEntries(repository,arguments.firstRevision,arguments.lastRevision);
			</cfscript>
			<cfif not isDefined('logEntries')>
				<cfset logentries ="Java Err!">
			</cfif>
		<cfcatch><cfdump var="#cfcatch#"><cfabort></cfcatch>
		</cftry>
		<cfdump var="#xmlParse(logEntries[1])#">
		<cfabort>
	</cffunction>

	<cffunction name="addResource" output="false" description="Fetch a log of a given revision" returntype="any">
		<cfargument name="resourceUrl" type="string" required="true">
		<cfargument name="message" type="string" required="true">
		<cfargument name="data" required="true">
			<cfscript>
				var repository = getRepository();
				var checksum = "";
				var commitMessage = arguments.message;
				var filedata = toBinary(toBase64(arguments.data));
				var filepath = arguments.resourceUrl;
				var dirpath = listDeleteAt(filepath,listLen(filepath,"/"),"/");
				var editor = repository.getCommitEditor(commitMessage,javacast("null",""));
				var deltaGenerator = variables._loader.create("org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator");
        editor.openRoot(javacast("int",-1));
        editor.openDir(javacast("string",dirPath), javacast("int",-1));
        /*
         * Adds a new file to the just added  directory. The  file  path is also 
         * defined as relative to the root directory.
         *
         * copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
         * (the 3rd parameter) is set to -1 since  the file is  not  added  with 
         * history.
         */
        editor.addFile(filePath, javacast("null",""), javacast("int",-1));
        /*
         * The next steps are directed to applying delta to the  file  (that  is 
         * the full contents of the file in this case).
         */
        editor.applyTextDelta(filePath, javacast("null",""));
        /*
         * Use delta generator utility class to generate and send delta
         * 
         * Note that you may use only 'target' data to generate delta when there is no 
         * access to the 'base' (previous) version of the file. However, using 'base' 
         * data will result in smaller network overhead.
         * 
         * SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
         * "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
         * Number of diff windows depends on the file size. 
         *  
         */
				inStream = CreateObject("java","java.io.ByteArrayInputStream").init(fileData);
        checksum = deltaGenerator.sendDelta(filePath, inStream, editor, true); 
        /*
         * Closes the new added file.
         */
        editor.closeFile(filePath, checksum);
        /*
         * Closes the root directory.
         */
        editor.closeDir();
        editor.closeDir();
        /*
         * This is the final point in all editor handling. Only now all that new
         * information previously described with the editor's methods is sent to
         * the server for committing. As a result the server sends the new
         * commit information.
         */
        retEdit = editor.closeEdit();
 			</cfscript>
			<cfreturn retEdit />
<!---
 			<cfdump var="#retEdit#">
		<cfabort>
 --->
	</cffunction>

	<cffunction name="addOrUpdateResource" output="false" description="Fetch a log of a given revision" returntype="any">
		<cfargument name="resourceUrl" type="string" required="true">
		<cfargument name="message" type="string" required="true">
		<cfargument name="data" required="true">
			<cfscript>
				var isRecursive = true; // recursivly add any directories that do not exist
				var repository = getRepository();
				var checksum = "";
				var commitMessage = arguments.message;
				var filedata = toBinary(toBase64(arguments.data));
				var filepath = resourcePath(repository,arguments.resourceUrl);
 				var dirpath = listDeleteAt(filepath,listLen(filepath,"/"),"/");
				var editor = "";
				var retEdit = "";
				var deltaGenerator = variables._loader.create("org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator");
				var props=CreateObject("java","java.util.HashMap").init(16);
				var out=CreateObject("java","java.io.ByteArrayOutputStream").init();
				var curDir = "/";
				var addDirs = "";
				var x = "";
				resourceURL = resourcePath(repository,resourceURL);

        for(x=1;x lte listLen(dirPath,"/");x=x+1) {
        	curDir = curDir & listGetAt(dirPath,x,"/") & "/";
          if (NOT resourceExists(repository,curDir)) {
          	dumpvar(curDir);
	        	addDirs = listAppend(addDirs,left(curDir,len(curDir)-1));
          }
        }
        dumpvar(addDirs);

		  	if(NOT resourceExists(repository,resourceUrl)) {
					editor = repository.getCommitEditor(commitMessage,javacast("null",""));
	        editor.openRoot(javacast("int",-1));
	        if(isRecursive) {
		        for(x=1;x lte listLen(addDirs);x=x+1) {
			        	editor.addDir(listGetAt(addDirs,x), javacast("null",""), javacast("int",-1));
				        editor.closeDir();
		        }
	        }

	        editor.openDir(javacast("string",dirPath), javacast("int",-1));
	        /*
	         * copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
	         * (the 3rd parameter) is set to -1 since  the file is  not  added  with 
	         * history.
	         */
	        editor.addFile(filePath, javacast("null",""), javacast("int",-1));
	        /*
	         * The next steps are directed to applying delta to the  file  (that  is 
	         * the full contents of the file in this case).
	         */
	        editor.applyTextDelta(filePath, javacast("null",""));
	        /*
	         * Use delta generator utility class to generate and send delta
	         * 
	         * Note that you may use only 'target' data to generate delta when there is no 
	         * access to the 'base' (previous) version of the file. However, using 'base' 
	         * data will result in smaller network overhead.
	         * 
	         * SVNDeltaGenerator will call editor.textDeltaChunk(...) method for each generated 
	         * "diff window" and then editor.textDeltaEnd(...) in the end of delta transmission.  
	         * Number of diff windows depends on the file size. 
	         *  
	         */
					inStream = CreateObject("java","java.io.ByteArrayInputStream").init(fileData);
	        checksum = deltaGenerator.sendDelta(filePath, inStream, editor, true);
	        /*
	         * Closes the new added file.
	         */
	        editor.closeFile(filePath, checksum);
		  	}
		  	// We will try to update, since something exists at the resourceURL
		  	else {
					repository.getFile(JavaCast("string",Arguments.ResourceUrl),JavaCast("int",-1),props,out);
					editor = repository.getCommitEditor(commitMessage,javacast("null",""));
	        editor.openRoot(javacast("int",-1));
	        editor.openDir(javacast("string",dirPath), javacast("int",-1));
	        editor.openFile(javacast("string",filePath), javacast("int",-1));
	        editor.applyTextDelta(filePath, javacast("null",""));
					newFileIS = CreateObject("java","java.io.ByteArrayInputStream").init(fileData);
					oldFileIS = CreateObject("java","java.io.ByteArrayInputStream").init(out.toByteArray());
	        checksum = deltaGenerator.sendDelta(filePath, oldFileIS, javacast("int",0), newFileIS, editor, true);
	        editor.closeFile(filePath, checksum);
		  	}

        /*
         * Closes the root directory.
         */
        editor.closeDir();
        editor.closeDir();
        /*
         * This is the final point in all editor handling. Only now all that new
         * information previously described with the editor's methods is sent to
         * the server for committing. As a result the server sends the new
         * commit information.
         */
        retEdit = editor.closeEdit();
 			</cfscript>
			<cfreturn retEdit />
<!---
 			<cfdump var="#retEdit#">
		<cfabort>
 --->
	</cffunction>

	<cffunction name="deleteResource" output="false" description="Fetch a log of a given revision" returntype="any">
		<cfargument name="resourceUrl" type="string" required="true">
		<cfargument name="message" type="string" required="true">
			<cfscript>
				var repository = getRepository();
				var checksum = "";
				var commitMessage = arguments.message;
				var filepath = arguments.resourceUrl;
 				var dirpath = listDeleteAt(filepath,listLen(filepath,"/"),"/");
        var nodeKind = repository.checkPath(JavaCast("string",arguments.resourceURL),JavaCast("int",-1));
				var editor = "";
				var retEdit = "";
				var deltaGenerator = variables._loader.create("org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator");
				var props=CreateObject("java","java.util.HashMap").init(16);
		  	if(NodeKind.compareTo(NodeKind.NONE) NEQ 0) {
					editor = repository.getCommitEditor(commitMessage,javacast("null",""));
	        editor.openRoot(javacast("int",-1));
	        editor.deleteEntry(filePath, javacast("int",-1));
		  	}
		  	// non-existant resource - nothing to delete
		  	else {
		  		return "nothing to delete";
		  	}

        /*
         * Closes the root directory.
         */
        editor.closeDir();
        retEdit = editor.closeEdit();
 			</cfscript>
			<cfreturn retEdit />
<!---
 			<cfdump var="#retEdit#">
		<cfabort>
 --->
	</cffunction>

	
	<cffunction name="createDirectory" output="false" description="Fetch a log of a given revision" returntype="any">
		<cfargument name="directory" type="string" required="true">
		<cfargument name="commitmessage" type="string" required="true">
			<cfscript>
				var repository = getRepository();
				var dirpath = arguments.directory;
        var nodeKind = repository.checkPath(JavaCast("string",dirpath),JavaCast("int",-1));
        var editor = "";
				var retEdit = "";
//        dumpvar(directory&"  " & commitMessage);
		  	if(NodeKind.compareTo(NodeKind.NONE) EQ 0) {
					editor = repository.getCommitEditor(arguments.commitMessage,javacast("null",""));
					try {
		        editor.openRoot(javacast("int",-1));
		        /*
		         * Adds a new directory  
		         * 
		         * dirPath is relative to the root directory.
		         * 
		         * copyFromPath (the 2nd parameter) is set to null and  copyFromRevision
		         * (the 3rd) parameter is set to  -1  since  the  directory is not added 
		         * with history (is not copied, in other words).
		         */
		        editor.addDir(dirpath, javacast("null",""), javacast("int",-1));
		        editor.closeDir();
		        editor.closeDir();
		        retEdit = editor.closeEdit();
					} catch(any except) {
						dumpvar(except);
					}
		  	}
		  	else {
		  		return "directory already exists";
		  	}
 			</cfscript>
			<cfreturn retEdit />
<!---
 			<cfdump var="#retEdit#">
		<cfabort>
 --->
	</cffunction>

	<cffunction name="modifyResource" output="false" description="Fetch a log of a given revision" returntype="query">
		<cfargument name="resourceUrl" type="string" required="true">
		<cfargument name="message" type="string" required="true">
		<cfargument name="data" required="true">
			<cfscript>
				var repository = getRepository();
				var checksum = "";
				var commitMessage = arguments.message;
				var filedata = toBinary(toBase64(arguments.data));
				var filepath = arguments.resourceUrl;
				var dirpath = listDeleteAt(filepath,listLen(filepath,"/"),"/");
				var editor = repository.getCommitEditor(commitMessage,javacast("null",""));
				var retEdit = "";
				var deltaGenerator = variables._loader.create("org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator");

				editor = repository.getCommitEditor(commitMessage,javacast("null",""));
				deltaGenerator = variables._loader.create("org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator"); 

        editor.openRoot(javacast("int",-1));
        editor.openDir(javacast("string",dirPath), javacast("int",-1));
        editor.openFile(javacast("string",filePath), javacast("int",-1));
        editor.applyTextDelta(filePath, javacast("null",""));
				newFileIS = CreateObject("java","java.io.ByteArrayInputStream").init(fileData);
				currentVersion = FileVersion(resourceUrl,-1);
				oldFileIS = CreateObject("java","java.io.ByteArrayInputStream").init(currentVersion.content);
        checksum = deltaGenerator.sendDelta(filePath, oldFileIS, javacast("int",0), newFileIS, editor, true);
        editor.closeFile(filePath, checksum);
        editor.closeDir();
        editor.closeDir();
        // run the commit
        retEdit = editor.closeEdit();
 			</cfscript>
			<cfdump var="#retEdit#">
		<cfabort>

	</cffunction>


	<cffunction name="Export" output="false" description="Fetch a log of a given revision" returntype="any">
		<cfargument name="resourceUrl" default="#variables._config.getConfigSetting("RepositoryURL")#">
		<cfargument name="exportRevision" default="head">
		<cfscript>
			/*	 doExport(SVNURL url,
                     File dstPath,
                     SVNRevision pegRevision,
                     SVNRevision revision,
                     String eolStyle,
                     boolean force,
                     boolean recursive)
              throws SVNException
       */
      var repoBaseURL = variables._config.getConfigSetting("RepositoryURL");
			var exportURL = repoBaseURL & "/" & replace(arguments.resourceUrl,repoBaseUrl,"","all");
			var targetDir = createObject("java","java.io.File").init(variables._config.getConfigSetting("exportDirectory") & resourceUrl);
			var pegRevision = variables._loader.create("org.tmatesoft.svn.core.wc.SVNRevision").parse(arguments.exportRevision);
			var revision = variables._loader.create("org.tmatesoft.svn.core.wc.SVNRevision").parse(arguments.exportRevision);
			var exporter = variables._loader.create("org.tmatesoft.svn.core.wc.SVNUpdateClient").init(getAuthManager(),javacast("null",""));
			exporter.doExport(this.svnurl.parseURIEncoded(exportURL),targetDir,pegRevision,revision,javacast("string","native"),true,true);
			return "exported";
		</cfscript>

	</cffunction>

	<cffunction name="zipExport" output="false" description="Fetch a log of a given revision" returntype="query">
		<cftry>
			<cfscript>
				zipExport = variables._loader.create('cfsvn.export.Exporter');
				dumpvar(zipExport.exportZip("wee"));
			</cfscript>
			<cfif not isDefined('logEntries')>
				<cfset logentries ="Java Err!">
			</cfif>
		<cfcatch><cfdump var="#cfcatch#"><cfabort></cfcatch>
		</cftry>
		<cfdump var="#logEntries#">
		<cfabort>
	</cffunction>

						
</cfcomponent>